home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #2 / Amiga Plus CD - 2004 - No. 02.iso / AmigaPlus / Tools / Development / AmigaTalk / general / BlockValue.st < prev    next >
Text File  |  2004-01-31  |  4KB  |  117 lines

  1. " -------------------------------------------------------------------------
  2.  
  3.   An instance of BlockValue represents a computation that propagates 
  4.   changes.  The value of an instance is recomputed by evaluating a block 
  5.   when the value of any of the instance's arguments changes.  All 
  6.   dependents are notified when the value has changed.
  7.  
  8.   Instance Variables:
  9.     block        <BlockClosure>
  10.     arguments    <SequenceableCollection of: ValueModel>
  11.     numArgs    <SmallInteger>    the number of arguments block takes
  12.  
  13.  
  14.   Object Reference:
  15.   A BlockValue computes its value using a given BlockClosure and a 
  16.   set of arguments for that block.  It registers itself as a dependent 
  17.   of each argument, so the arguments are typically value models. 
  18.   Whenever any of the argument objects changes its value, the BlockValue 
  19.   is updated.  The result is similar to sending #onChangeSend:to: 
  20.   to each of the argument objects, asking them to trigger a method that 
  21.   updates a particular value.  Using a BlockValue eliminates the need 
  22.   to create the method that is triggered -- instead, the block is 
  23.   evaluated with the changed arguments.  The resulting value is cached 
  24.   so that it need not be recomputed unless one of the block arguments 
  25.   changes again.  Being able to use a block instead of a method is 
  26.   especially helpful in the case of dialog that has been built from 
  27.   scratch, such that a method in the application model would have 
  28.   difficulty accessing some of the data in the dialog for its computation.
  29.   A BlockValue is typically created by sending #block:arguments: to 
  30.   this class.  The ValueModel class also provides a set of methods for 
  31.   conveniently spawning a BlockValue from one of the argument objects 
  32.   (see the constructing protocol in ValueModel).
  33.   By default, a BlockValue recomputes its cached value whenever it is 
  34.   notified that one of the block arguments has changed.  This is known 
  35.   as eager evaluation.  In some situations, late evaluation may be 
  36.   preferable -- then, the cached value is only recomputed when it is 
  37.   requested via #value (assuming one of the block arguments has changed). 
  38.   Late evaluation can be arranged by sending an #eagerEvaluation: 
  39.   message to the BlockValue with false as the argument.  This is most 
  40.   useful when the cached value is only requested infrequently and the 
  41.   block computation is costly in terms of time or other resources. 
  42.   -------------------------------------------------------------------------
  43. "
  44.  
  45. Class BlockValue :ComputedValue  ! myBlock arguments numArgs !
  46. [
  47.    block: aBlock arguments: aCollection
  48.      " Answer an instance of the receiver with aCollection as arguments "
  49.  
  50.      ^ self new setBlock: aBlock arguments: aCollection
  51. |
  52.    with: aBlock
  53.      " Answer a new instance of the receiver that computes aBlock. "
  54.  
  55.      ^ self new setBlock: aBlock arguments: SequenceableCollection new
  56. |
  57.    dependOn: anObject
  58.      " Make the receiver depend on anObject. "
  59.  
  60.      anObject addDependent: self.
  61.  
  62.      arguments <- self parts copyWith: anObject
  63. |
  64.    parts
  65.      " Answer a collection of objects that have 
  66.      * the receiver as a dependent.
  67.      "
  68.      (arguments == nil)
  69.         ifTrue: [ arguments <- Array new].
  70.  
  71.      ^ arguments
  72. |
  73.    computeValue ! array !
  74.      " Compute a value for the receiver. "
  75.  
  76.      (0 = numArgs) 
  77.        ifTrue: [ ^ myBlock value].
  78.      
  79.      (1 = numArgs)
  80.        ifTrue: [ ^ myBlock value: (arguments at: 1) value].
  81.      
  82.      (2 = numArgs) 
  83.        ifTrue: [ ^ myBlock value: (arguments at: 1) value 
  84.                            value: (arguments at: 2) value ].
  85.      
  86.      (3 = numArgs)
  87.        ifTrue: [ ^ myBlock value: (arguments at: 1) value
  88.                            value: (arguments at: 2) value
  89.                            value: (arguments at: 3) value ].
  90.                         
  91.      array <- Array new: (numArgs min: arguments size).
  92.      
  93.      1 to: array size do: [:i | array at: i put: (arguments at: i) value].
  94.  
  95.      ^ myBlock valueWithArguments: array
  96. |
  97.    setBlock: aBlock
  98.      " Set the block for the receiver to be aBlock. "
  99.  
  100.      myBlock     <- aBlock.
  101.      numArgs     <- myBlock numArgs.
  102.  
  103.      super resetCache.              "cachedValue <- UnassignedValue. "
  104.  
  105.      arguments   <- #().
  106. |
  107.    setBlock: aBlock arguments: aCollection
  108.      " Set the receiver's block to be aBlock and 
  109.      * the arguments to be aCollection.
  110.      "
  111.      self setBlock: aBlock.
  112.  
  113.      arguments <- aCollection.
  114.  
  115.      1 to: arguments size do: [:i | (arguments at: i) addDependent: self]
  116. ]
  117.